import axios from 'axios';
import chalk from 'chalk';
import path from 'path';
import fs from 'fs';
import iconv from 'iconv-lite';
import request from 'request';
import lodash from 'lodash';
import console from 'console';

const log = console.log;
const __dirname = path.resolve();

/**
 * 将普通对象转换成form对象
 * @param obj {{appId: config.appId, appBranch: config.appBranch }}
 */
function transformObjToURLSearchParams(obj) {
  const params = new URLSearchParams('');
  Object.keys(obj).forEach((key) => {
    params.append(key, obj[key]);
  });
  return params;
};

/**
 * 从接口http://cowork.apexsoft.com.cn/plug-in/cowork/apiCommonService.jsp?MOD=queryApilist获取接口分类相关信息
 * @param params {{ appId: config.appId, appBranch: config.appBranch} }
 */
function fetchAllApiInfo(params, config) {
  return axios({
    url: 'http://cowork.apexsoft.com.cn/plug-in/cowork/apiCommonService.jsp?MOD=queryApilist',
    method: 'post',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
      Cookie: config.COOKIE,
      // 这里其他系统可能需要更改,具体可去浏览器中network中查看
      "User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
    },
    data: transformObjToURLSearchParams(params),
  })
    .then((response) => {
      if (response.status === 200) {
        return response.data;
      }
    })
    .then((res) => {
      if (res && res.CODE === '0') {
        return res.RESULT || [];
      } else {
        log(chalk.red('获取全部接口列表失败'));
      }
    })
    .catch((error) => {
      log(chalk.red('fetchAllApiInfo error', error));
    });
};

/**
 * 格式化全部api信息, 提取有用信息如接口分类名称fileName 接口分类描述fileDis, 该分类下的apiCode
 */
function formatAllApiInfo(allApiInfo) {
  return allApiInfo.map(apiInfo => {
    const { name = '', children = [] } = apiInfo;
    const [fileDis, fileName] = name.split('/');
    return ({
      fileDis, fileName,
      children: children.map(item => item.apiCode),
    });
  });
};

/**
 *根据apiCode获取每个接口详细信息，如描述、出参、入参、url等
 */
function fetchApiDefineInfo(apiCode, config, DEFAULT_PARAMS) {
  // 使用request与iconv处理乱码问题
  return new Promise((resolve, reject) => {
    request(
      {
        url: `http://cowork.apexsoft.com.cn/plug-in/cowork/apiCommonService.jsp?MOD=readApiDefine&appBranch=${config.appBranch}&type=1`,
        method: 'post',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
          Cookie: config.COOKIE,
          // 这里其他系统可能需要更改,具体可去浏览器中network中查看
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
        },
        encoding: null,
        form: {
          ...DEFAULT_PARAMS,
          type: 1,
          apiCode,
        },
      },
      (err, status, resData) => {
        try {
          const decodeData = JSON.parse(iconv.decode(resData, 'gbk'));
          resolve(toFormatData(decodeData?.data || []));
        } catch (error) {
          return reject(error);
        }
      },
    );
  });
};

/**
 * 格式化数据，提取有用的信息，如入参、出参、url、描述等
 */
function toFormatData(dataArr) {
  function getValue(path) {
    return lodash.get(dataArr, path, '');
  }
  try {
    const key = getValue('[0][1]["v"]');
    const dis = getValue('[1][1]["v"]');;
    const url = getValue('[3][1]["v"]');
    const method = getValue('[3][7]["v"]');
    const input = [];
    const output = [];

    const inputFirstIndex = dataArr.findIndex(
      (item) => lodash.get(item, '[0]["v"]') === "输入参数"
    );
    const inputLastIndex = dataArr.findIndex(
      (item) => lodash.get(item, '[0]["v"]') === "输出参数"
    );
    for (let i = inputFirstIndex; i < inputLastIndex; i++) {
      if (getValue(`[${i}][1]["v"]`)) {
        const dis = `${getValue(`[${i}][1]["v"]`)}${getValue(`[${i}][6]["v"]`)}${getValue(`[${i}][7]["v"]`)}`; //字段中文名 描述
        const isRequire = getValue(`[${i}][5]["v"]`); // 是否必须
        const name =
          isRequire === "Y" ? getValue(`[${i}][2]["v"]`) : `${getValue(`[${i}][2]["v"]`)}?`; // 字段名
        const valueType = "string"; // http中接口入参即使是其他类型也会被序列化成string
        input.push({ name, nameType: valueType, dis: dis.replaceAll('null', '') });
      }
    }

    const outputType = getValue(`[${inputLastIndex + 2}][1]["v"]`, '')
      ? getValue(`[${inputLastIndex + 2}][2]["v"]`, '')
      : "";

    let outoutLastIndex = dataArr.findIndex(
      (item) => lodash.get(item, '[0]["v"]', '') === "修改记录"
    );
    outoutLastIndex = outoutLastIndex === -1 ? dataArr.length : outoutLastIndex;
    for (let i = inputLastIndex + 2; i < outoutLastIndex; i++) {
      if (getValue(`[${i}][5]["v"]`)) {
        const dis = `${getValue(`[${i}][4]["v"]`)}${getValue(`[${i}][7]["v"]`)}`; //字段中文名 描述
        const name = getValue(`[${i}][5]["v"]`); // 字段名
        const valueType = getValue(`[${i}][6]["v"]`); // 字段类型
        output.push({ name, nameType: formatType(valueType), dis: dis.replaceAll('null', '') });
      }
    }
    return {
      key,
      dis,
      url,
      method,
      input,
      output,
      outputType,
    };
  } catch (err) {
    log(chalk.red(`解析数据异常:`, err));
    process.exit(0);
  }
}

// 检查并创建文件
function ensureFileAndDirExist(filePath) {
  const directory = path.dirname(filePath);
  try {
    // 先检查目录是否存在
    fs.accessSync(directory, fs.constants.F_OK);
  } catch (err) {
    // 如果目录不存在，则创建
    try {
      fs.mkdirSync(directory, { recursive: true });
    } catch (error) {
      console.log('文件目录创建失败', error);
      process.exit(0);
    }
  }
  // 再检查文件是否存在 存在则清空文件内容
  try {
    fs.accessSync(filePath, fs.constants.F_OK);
    fs.truncateSync(filePath, 0);
  } catch (err) {
    // 如果文件不存在
  }
}

// 写入api文件内
function toWriteApiFile(fileName, fileDis, apiDefineInfoArr, config) {
  // 1.检查文件夹以及文件是否存在，存在则清空文件内容，不存在则先创建
  const dir = path.join(__dirname, config.apiFolderPath);
  const filePath = path.join(dir, `${fileName}\\${fileName}.ts`);
  ensureFileAndDirExist(filePath);
  if (apiDefineInfoArr.length) {
    const apiStr = generateApiStr(fileDis, apiDefineInfoArr);
    fs.writeFileSync(filePath, apiStr);
  } else {
    log(chalk.red(`写入api文件失败：${filePath}`));
    process.exit(0);
  }
}

// 写入services文件内
function toWriteServicesFile(fileName, fileDis, apiDefineInfoArr, config) {
  // 1.检查文件夹以及文件是否存在，存在则清空文件内容，不存在则先创建
  const dir = path.join(__dirname, config.servicesFolderPath);
  const filePath = path.join(dir, `${fileName}\\${fileName}.ts`);
  ensureFileAndDirExist(filePath);
  if (apiDefineInfoArr.length) {
    const apiStr = generateServiceStr(fileName, apiDefineInfoArr);
    fs.writeFileSync(filePath, apiStr);
  } else {
    log(chalk.red(`写入services文件失败：${filePath}`));
  }
}

// 生成api模板字符串
function generateApiStr(fileDis, apiDefineInfoArr) {
  return `
// ${fileDis}
export default [
${apiDefineInfoArr
    .map(
      (item) => generateOneApi(item),
    )
    .join('\n')}
]
`;
};

function generateOneApi(item) {
  return `\t{ key: '${item.key}', url: '${item.url}', dis: '${item.dis}', method: '${item.method}' },`;
}

// 生成services模板字符串
function generateOneService(item, flag) {
  const { key = '', url = '', dis = '', method = 'GET', input = [], output = [], outputType = '' } = item;
  const FetchName = key.charAt(0).toUpperCase() + key.slice(1);
  const outputStr = ['records'].includes(outputType) ? '[]' : '';
  const recordsStr = outputType !== '' ? `${outputType}: {\n${formatOutputStr(output)}\t}${outputStr}
}` : '';
  return `\ntype ${FetchName}Input = {
${formatInputStr(input)}}
type ${FetchName}Output = {
  code: number,
  note: string,
  ${recordsStr};
// ${dis}
export async function ${FetchName}(payload: ${FetchName}Input): Promise<${FetchName}Output> {
  const option = {
    url: ${key}, // ${url}
    method: '${method}',
    data: payload,
  };
  return request(option);
}\n`;
};

function generateServiceStr(fileName, apiDefineInfoArr) {
  let res = `import request from '../../utils/request';
import config from '../../utils/config';

const { api } = config;
const { ${fileName}: {
  ${apiDefineInfoArr.map(item => item.key).join(',\n  ')},
} } = api;
`;
  apiDefineInfoArr.forEach((item, index) => {
    res += generateOneService(item);
  });
  return res;
};

// 格式化入参
function formatInputStr(arr) {
  let str = '';
  arr.forEach((item, index) => {
    const { name, nameType, dis } = item;
    str += `\t${name}: ${nameType}, \/\/ ${dis}${index !== arr.length && '\n'}`;
  });
  return `${str}`;
};
// 格式化出参
const formatOutputStr = (arr) => {
  let str = '';
  arr.forEach((item, index) => {
    const { name, nameType, dis } = item;
    str += `\t\t${name}: ${nameType},${dis ? '\t//' : ''}${dis}${index !== arr.length && '\n'}`;
  });
  return `${str}`;
};

// 将后端接口返回的字段类型转成js存在的类型
function formatType(type) {
  if (type === 'String') {
    return 'string';
  } else if (['Long', 'Integer', 'Number', 'Double', 'Float'].includes(type)) {
    return 'number';
  } else if (['Map<String>', 'List<>', 'List<Map>', 'Map<Integer>']) {
    return 'Array<any>';
  } else {
    return 'unknow';
  }
};


// 替换文件内特定的容并重新写入到文件中(针对api文件)
function replaceApiFileContent(filePath, beReplaceKey, newStr) {
  const content = fs.readFileSync(filePath, 'utf-8');
  const lines = content.split('\n');
  const index = lines.findIndex(line => line.includes(beReplaceKey));
  if (index > -1) {
    lines[index] = newStr;
  } else {
    lines[lines.length - 2] = `${newStr}\n]`;
  }
  fs.writeFileSync(filePath, lines.join('\n'));
}

// 替换文件内特定的容并重新写入到文件中(针对services文件)
function replaceServiceFileContent(filePath, apiCode, newStr) {
  // const content = fs.readFileSync(filePath, 'utf-8');
  const newApiCode = apiCode.charAt(0).toUpperCase() + apiCode.slice(1);
  const oldString = new RegExp(`\\ntype ${newApiCode}([\\s\\S]*?)return request\\(option\\);\\n}\\n`, 'g');
  // 读取文件内容
  fs.readFile(filePath, 'utf8', (err, data) => {
    if (err) {
      console.error('读取文件时出错:', err);
      return;
    }
    // 检查旧字符串是否存在
    const regex = new RegExp(oldString, 'g');
    const hasMatch = regex.test(data);

    let updatedData = data;

    if (hasMatch) {
      // 如果匹配到旧字符串，则替换它
      updatedData = data.replace(regex, newStr);
    } else {
      updatedData = updatedData.replace('} } = api;', `\t${apiCode},\n} } = api;`);
      // 如果没有匹配到旧字符串，则在文件末尾添加新字符串
      updatedData += newStr;
    }

    // 将更新后的内容写回文件
    fs.writeFile(filePath, updatedData, 'utf8', (err) => {
      if (err) {
        console.error('写入文件时出错:', err);
        return;
      }
      // console.log('文件内容已成功更新或添加！');
    });
  });
}

export {
  fetchAllApiInfo, fetchApiDefineInfo, toWriteApiFile, toWriteServicesFile, formatAllApiInfo, toFormatData,
  replaceApiFileContent, replaceServiceFileContent, generateOneApi, generateOneService,
};